use log::info;
use poker_lib::Suit;

use crate::{round::Round, seat::Seat, table::Table, turn::TurnBidState, utils::Utils};

pub trait IAiBidMode {
    fn get_turn_bid_state(
        &self,
        player_id: usize,
        table: &Table,
        round: &Round,
        final_score: i16,
        bag_limit: i16,
    ) -> TurnBidState;

    fn get_ak_num(&self, seat: &Seat) -> i16;
    fn is_can_bid_nil(
        &self,
        suit_rank_bid: f32,
        seat: &Seat,
        bid_state: &TurnBidState,
        final_score: f32,
    ) -> bool;
    fn get_bid_normal(&self, seat: &Seat) -> f32;
    fn get_bid_suit_spades(&self, seat: &Seat) -> f32;
    fn get_bid_with_hard_diff(
        &self,
        seat: &Seat,
        table: &Table,
        round: &Round,
        final_score: i16,
    ) -> i16;
}

pub struct AiBidNormal;

impl IAiBidMode for AiBidNormal {
    fn get_turn_bid_state(
        &self,
        player_id: usize,
        table: &Table,
        round: &Round,
        final_score: i16,
        bag_limit: i16,
    ) -> TurnBidState {
        let mut turn_bid_state = TurnBidState::new();
        let leading_player_id = round.bid_leader();
        let num = Utils::get_next_player_id(leading_player_id);
        let num2 = Utils::get_prev_player_id(leading_player_id);

        if player_id == leading_player_id {
            turn_bid_state.is_leading_player = true;
        } else if player_id == num2 {
            let player = round.get_player_by_id(Utils::get_prev_player_id(player_id));
            let player2 = round.get_player_by_id(leading_player_id);
            let player3 = round.get_player_by_id(Utils::get_partner_player_id(player_id));
            turn_bid_state.is_last_player_bid = true;
            turn_bid_state.partner_bid = player3.bid.unwrap();
            turn_bid_state.leading_bid = player2.bid.unwrap();
            turn_bid_state.pre_player_bid = player.bid.unwrap();
        } else if player_id == num {
            let player4 = round.get_player_by_id(leading_player_id);
            turn_bid_state.pre_player_bid = player4.bid.unwrap();
        } else {
            let player5 = round.get_player_by_id(Utils::get_prev_player_id(player_id));
            let player6 = round.get_player_by_id(Utils::get_partner_player_id(player_id));
            turn_bid_state.is_leading_partner = true;
            turn_bid_state.pre_player_bid = player5.bid.unwrap();
            turn_bid_state.partner_bid = player6.bid.unwrap();
        }
        let rounds = &table.rounds;
        let round_result = rounds.last();

        if let Some(round_result) = round_result {
            let team = round.get_team_by_player_id(player_id, 1);
            let team_score = round_result.teams[team];
            turn_bid_state.team_match_score = team_score.match_score;
            turn_bid_state.team_total_bags = team_score.total_bags;

            let other_team = round.get_other_team_by_team_id(team);
            let other_team_score = &round_result.teams[other_team];
            turn_bid_state.other_match_score = other_team_score.match_score;
            turn_bid_state.other_total_bags = other_team_score.total_bags;
        }
        turn_bid_state.team_final_left_score = final_score - turn_bid_state.team_match_score;
        turn_bid_state.other_final_left_score = final_score - turn_bid_state.other_match_score;
        turn_bid_state.team_bags_dt = bag_limit - turn_bid_state.team_total_bags;
        turn_bid_state.other_bags_dt = bag_limit - turn_bid_state.other_total_bags;

        turn_bid_state
    }

    fn get_ak_num(&self, seat: &Seat) -> i16 {
        let mut num: i16 = 0;
        for card in &seat.cards.cards {
            let (_t, n) = card.get_suit_num();
            if n == 1 || n == 13 {
                num += 1;
            }
        }
        num
    }

    fn is_can_bid_nil(
        &self,
        suit_rank_bid: f32,
        seat: &Seat,
        bid_state: &TurnBidState,
        final_score: f32,
    ) -> bool {
        if suit_rank_bid > 1.34 {
            return false;
        }
        if (bid_state.is_leading_partner || bid_state.is_last_player_bid)
            && bid_state.partner_bid == 0
        {
            return false;
        }
        //spades >= 3 or has J Q K A
        let mut sc = &seat.cards[Suit::Spade];
        let count = sc.n;

        if count >= 3
            || sc.bucket[11] > 0
            || sc.bucket[12] > 0
            || sc.bucket[13] > 0
            || sc.bucket[1] > 0
        {
            return false;
        }
        // has joker
        sc = &seat.cards[Suit::Joker];
        if sc.n > 0 {
            return false;
        }
        let final_p_40 = final_score * 0.4;
        let final_p_20 = final_score * 0.2;

        if !bid_state.is_leading_player && bid_state.pre_player_bid == 0 {
            return false;
        }
        if (bid_state.team_match_score - bid_state.other_match_score) as f32 >= final_p_40 {
            return false;
        }
        if bid_state.team_final_left_score as f32 <= final_p_20 {
            return false;
        }

        // has J Q K J not bid 0
        for index in 0..=3u8 {
            let suit = Suit::from_u8(index).unwrap();
            let sc = &seat.cards[suit];
            if sc.n > 0 {
                //some suit has A and count < 3 or  has no 2 3 4
                if sc.bucket[1] > 0 && sc.n <= 3
                    || sc.bucket[2] == 0 && sc.bucket[3] == 0 && sc.bucket[4] == 0
                {
                    return false;
                }
                //some suit only one but >=J
                if sc.n == 1
                    && (sc.bucket[11] > 0
                        || sc.bucket[12] > 0
                        || sc.bucket[13] > 0
                        || sc.bucket[1] > 0)
                {
                    return false;
                }
            }
        }
        if (bid_state.team_match_score + bid_state.other_match_score) as f32 <= final_p_40 {
            return true;
        }
        if (bid_state.team_match_score - bid_state.other_match_score) as f32 <= final_p_20 {
            return true;
        }
        if bid_state.partner_bid >= 4 || bid_state.pre_player_bid >= 4 {
            return true;
        }
        if bid_state.is_last_player_bid && bid_state.leading_bid == 0 {
            return true;
        }
        false
    }
    fn get_bid_normal(&self, seat: &Seat) -> f32 {
        let mut num: f32 = 0.0;
        let spades_bid = self.get_bid_suit_spades(seat) + seat.cards[Suit::Joker].n as f32;
        let mut spades_left: f32 =
            (seat.cards[Suit::Spade].n + seat.cards[Suit::Joker].n) as f32 - spades_bid;
        info!(
            "--robot {}  黑桃计算bid后剩余可用数 spades_left : {}",
            seat.id, spades_left
        );

        for index in 1..=3u8 {
            let suit = Suit::from_u8(index).unwrap();
            let cs = &seat.cards[suit];
            let count = cs.n as f32;
            let last_bid = num;
            info!(
                "--robot {}  bid 计算花色{} 开始{} ",
                seat.id,
                suit.to_string(),
                suit.to_string(),
            );
            if cs.bucket[1] > 0 {
                if count < 7.0 {
                    num += 1.0;
                    info!(
                        "--robot {} {} bid +{}->{} reason : {:?}",
                        seat.id,
                        suit.to_string(),
                        1,
                        num,
                        "该花色有 A ,并且该花色数量小于7"
                    );
                } else if count < 8.0 {
                    num += 0.51;
                    info!(
                        "--robot {} {} bid +{}->{} reason : {:?}",
                        seat.id,
                        suit.to_string(),
                        0.51,
                        num,
                        "该花色有 A ,并且该花色数量有6张"
                    );
                } else {
                    num += 0.33;
                    info!(
                        "--robot {} {} bid +{}->{} reason : {:?}",
                        seat.id,
                        suit.to_string(),
                        0.33,
                        num,
                        "该花色有 A ,并且该花色数量有8张以上"
                    );
                }
            }
            if cs.bucket[13] > 0 {
                if count > 1.0 {
                    if count < 5.0 {
                        num += 1.0;
                        info!(
                            "--robot {} {} bid +{}->{} reason : {:?}",
                            seat.id,
                            suit.to_string(),
                            1,
                            num,
                            "该花色有 K ,并且该花色数量 大于1 小于5"
                        );
                    } else if count < 6.0 {
                        num += 0.51;
                        info!(
                            "--robot {} {} bid +{}->{} reason : {:?}",
                            seat.id,
                            suit.to_string(),
                            0.51,
                            num,
                            "该花色有 K ,该花色数量5张"
                        );
                    } else if count < 7.0 {
                        num += 0.34;
                        info!(
                            "--robot {} {} bid +{}->{} reason : {:?}",
                            seat.id,
                            suit.to_string(),
                            0.34,
                            num,
                            "该花色有 K ,并且该花色数量6张"
                        );
                    } else {
                        num += 0.25;
                        info!(
                            "--robot {} {} bid +{}->{} reason : {:?}",
                            seat.id,
                            suit.to_string(),
                            0.25,
                            num,
                            "该花色有 K ,并且该花色数量6张"
                        );
                    }
                }
                // else {
                //     num += 0.33;
                //     info!(
                //         "--robot {} {} bid +{}->{} reason : {:?}",
                //         seat.id,
                //         suit.to_string(),
                //         0.33,
                //         num,
                //         "该花色有 K ,并且该花色数量1张"
                //     );
                // }
            }
            if cs.bucket[12] > 0 {
                if count >= 3.0 {
                    //花色多了 Q不一定能有收益
                    num += 0.33;
                    info!(
                        "--robot {} bid +{}->{} reason : {:?}",
                        seat.id, 0.51, num, "该花色有 Q ,并且该花色数量 大于等于3"
                    );
                }
                //试试有Q 也进行花色少的判断
                info!(
                    "--robot {} 不进行空缺判定和break判定 reason : {}",
                    seat.id, "该花色有 Q "
                );
                continue;
            }
            //杀牌优先的情况下需要提下 副花色少的权重
            // if count == 2.0 {
            //     if spades_left > 0.0 {
            //         num += 0.5;
            //         let last_spades_left = spades_left;
            //         spades_left -= 0.5;
            //         info!(
            //             "--robot {} bid +{}->{} reason : {:?}{}->{}",
            //             seat.id,
            //             0.5,
            //             num,
            //             "该花色只有两张 ,并且黑桃有剩余:",
            //             last_spades_left,
            //             spades_left
            //         );
            //     }
            // } else
            if count == 1.0 {
                //该花色只有一张
                if spades_left > 0.0 {
                    num += 1.0;
                    let last_spades_left = spades_left;
                    spades_left -= 1.0;
                    info!(
                        "--robot {} bid +{}->{} reason : {:?}{}->{}",
                        seat.id,
                        1,
                        num,
                        "该花色只有一张 ,并且黑桃有剩余:",
                        last_spades_left,
                        spades_left
                    );
                }
            } else if count == 0.0 {
                //没有该花色
                if spades_left > 1.0 {
                    num += 1.5;
                    let last_spades_left = spades_left;
                    spades_left -= 1.5;
                    info!(
                        "--robot {} bid +{}->{} reason : {:?}{}->{}",
                        seat.id,
                        1,
                        num,
                        "该花色空缺 ,并且黑桃剩余大于1张:",
                        last_spades_left,
                        spades_left
                    );
                }
            }
            info!(
                "--robot {}  bid 计算花色{}结束 {}bid {:?} 副花色 bid {}",
                seat.id,
                suit.to_string(),
                suit.to_string(),
                num - last_bid,
                num
            );
        }
        info!(
            "robot {}  bid 结束: 黑桃主牌bid {:?} + 副花色bid {} = {}",
            seat.id,
            spades_bid,
            num,
            num + spades_bid
        );
        (num + spades_bid).ceil()
    }
    fn get_bid_suit_spades(&self, seat: &Seat) -> f32 {
        info!(
            "--robot {}  bid : {} cards : {:?}",
            seat.id, "计算黑桃bid开始", seat.cards
        );
        let mut num: f32 = 0.0;
        let sc = &seat.cards[Suit::Spade];
        let count = sc.n as f32;
        let has_a = sc.bucket[1] > 0;
        let has_k = sc.bucket[13] > 0;
        let has_q = sc.bucket[12] > 0;
        let has_j = sc.bucket[11] > 0;
        if has_a {
            num += 1.0;
            info!(
                "--robot {}  bid +{}->{} reason : {:?}",
                seat.id, 1, num, "有黑桃A"
            );
            if has_q && count >= 3.0 {
                num += 1.0;
                info!(
                    "--robot {}  bid +{}->{} reason : {:?}",
                    seat.id, 1, num, "有黑桃A和黑桃Q,并且黑桃3张以上"
                );
            }
        } else if has_q && count >= 3.0 {
            num += 1.0;
            info!(
                "--robot {}  bid +{}->{} reason : {:?}",
                seat.id, 1, num, "没有黑桃A有黑桃Q,并且黑桃3张以上"
            );
        }
        let mut is_j_add = false;
        if has_k {
            if count >= 2.0 {
                num += 1.0;
                info!(
                    "--robot {}  bid +{}->{} reason : {:?}",
                    seat.id, 1, num, "有黑桃K,并且黑桃2张以上"
                );
            }
            if has_j && count >= 4.0 {
                num += 1.0;
                is_j_add = true;
                info!(
                    "--robot {}  bid +{}->{} reason : {:?}",
                    seat.id, 1, num, "有黑桃K和黑桃J,并且黑桃4张以上"
                );
            }
        }
        if has_j && !is_j_add && count >= 5.0 {
            num += 0.5;
            info!(
                "--robot {}  bid +{}->{} reason : {:?}",
                seat.id, 0.5, num, "有黑桃J,并且黑桃5张以上"
            );
        }
        if count >= 4.0 {
            let add = (count - 3.0) * 0.3;
            num += add;
            info!(
                "--robot {}  bid +{}->{} reason : {:?}",
                seat.id, add, num, "有黑桃4张以上"
            );
        }
        if num > count {
            num = count;
            info!(
                "--robot {}  bid fix{}->{} reason : {:?}",
                seat.id, num, count, "如果黑桃bid超过了黑桃张数,修正为黑桃张数"
            );
        }
        info!(
            "--robot {}  bid {} {}",
            seat.id,
            "计算黑桃bid结束 黑桃贡献bid ",
            { num }
        );
        num
    }

    fn get_bid_with_hard_diff(
        &self,
        seat: &Seat,
        table: &Table,
        round: &Round,
        final_score: i16,
    ) -> i16 {
        let sr_bid = self.get_bid_normal(seat);
        let bag_limit = table.limit_bag;
        // let final_score_fix = final_score as f32 * 0.4;
        let num = sr_bid;
        let player_id = seat.id;
        let turn_bid_state =
            self.get_turn_bid_state(player_id, table, round, final_score, bag_limit);
        if self.is_can_bid_nil(sr_bid, seat, &turn_bid_state, final_score as f32) {
            return 0;
        }
        // let mut num2 = 0.0;
        // if turn_bid_state.team_match_score < turn_bid_state.other_match_score {
        //     if turn_bid_state.other_match_score
        //         + 10 * (turn_bid_state.leading_bid + turn_bid_state.pre_player_bid) as i16
        //         >= final_score
        //     {
        //         //预测可能是最后一轮 多叫1分 机器人会减少避袋
        //         num2 = 1.0;
        //     } else if (turn_bid_state.other_match_score - turn_bid_state.team_match_score) as f32
        //         >= final_score_fix
        //     {
        //         num2 = 1.0;
        //     }
        //     if turn_bid_state.other_total_bags >= bag_limit - 2 {
        //         num2 -= 1.4;
        //     } else if turn_bid_state.other_total_bags >= bag_limit - 3 {
        //         num2 += 0.4;
        //     }
        // } else if turn_bid_state.other_total_bags >= bag_limit - 3 {
        //     num2 = -1.1;
        // }
        // if turn_bid_state.is_leading_partner || turn_bid_state.is_last_player_bid {
        //     // if turn_bid_state.partner_bid == 0 {
        //     //     num2 -= 1.0;
        //     // }
        //     if num > 3.0 {
        //         if turn_bid_state.partner_bid >= 5 {
        //             num2 -= 0.5;
        //             if turn_bid_state.partner_bid >= 6 {
        //                 num2 -= 0.4;
        //                 if turn_bid_state.partner_bid >= 7 {
        //                     num2 -= 0.4;
        //                 }
        //             }
        //         }
        //     }
        // }
        // if turn_bid_state.is_last_player_bid && turn_bid_state.leading_bid >= 4 {
        //     if num >= 4.0 {
        //         num2 -= 0.4;
        //     }
        // }
        // if table.rounds.len() < 5
        //     && (turn_bid_state.team_match_score + turn_bid_state.other_match_score) as f32
        //         <= final_score_fix
        //     && turn_bid_state.partner_bid != 0
        // {
        //     num2 += 0.4;
        // }
        // num += num2;
        // let mut num3 = if (turn_bid_state.team_match_score as f32) < final_score_fix {
        //     (num + 0.501).floor() as i16
        // } else {
        //     (num + 0.499).floor() as i16
        // };
        let mut num3 = num as i16;
        if turn_bid_state.is_last_player_bid {
            let num4 = turn_bid_state.leading_bid
                + turn_bid_state.partner_bid
                + turn_bid_state.pre_player_bid;
            if num4 + num3 > 13 {
                let mut num5 = 13 - num4;
                if num5 <= 0 {
                    num5 = 1;
                }
                num3 = if num3 - num5 > 3 { num3 - 3 } else { num5 };
            }
        }
        // //Q K A 多 校正下但是叫分少的情况
        // let player = round.get_player_by_id(player_id);
        // let num6 = get_greater_queen_card_num(&player.cards.cards);
        // let num7 = num3 - num6;
        // if num7 <= -2 {
        //     num3 = num6 - 1;
        // }
        // 队友叫牌总数不能超过13
        let overflow = num3 + turn_bid_state.partner_bid - 13;
        if overflow > 0 {
            num3 = if num3 > overflow { num3 - overflow } else { 1 };
        }
        if num3 <= 0 {
            num3 = 1;
        }
        return num3;
    }
}

pub struct AiBidSolo {
    pub normal: AiBidNormal, // Composition with IAiBidNormal
}

impl IAiBidMode for AiBidSolo {
    fn get_turn_bid_state(
        &self,
        player_id: usize,
        _table: &Table,
        round: &Round,
        _final_score: i16,
        _bag_limit: i16,
    ) -> TurnBidState {
        let mut turn_bid_state = TurnBidState::new();
        let leading_player_id = round.bid_leader();
        let num = Utils::get_next_player_id(leading_player_id);
        let num2 = Utils::get_prev_player_id(leading_player_id);

        if player_id == leading_player_id {
            turn_bid_state.is_leading_player = true;
        } else if player_id == num2 {
            let player = round.get_player_by_id(Utils::get_prev_player_id(player_id));
            let player2 = round.get_player_by_id(leading_player_id);
            let player3 = round.get_player_by_id(Utils::get_partner_player_id(player_id));
            turn_bid_state.is_last_player_bid = true;
            turn_bid_state.partner_bid = player3.bid.unwrap();
            turn_bid_state.leading_bid = player2.bid.unwrap();
            turn_bid_state.pre_player_bid = player.bid.unwrap();
        } else if player_id == num {
            let player4 = round.get_player_by_id(leading_player_id);
            turn_bid_state.pre_player_bid = player4.bid.unwrap();
        } else {
            let player5 = round.get_player_by_id(Utils::get_prev_player_id(player_id));
            let player6 = round.get_player_by_id(Utils::get_partner_player_id(player_id));
            turn_bid_state.is_leading_partner = true;
            turn_bid_state.pre_player_bid = player5.bid.unwrap();
            turn_bid_state.partner_bid = player6.bid.unwrap();
        }
        turn_bid_state
    }

    fn get_ak_num(&self, seat: &Seat) -> i16 {
        self.normal.get_ak_num(seat) // Delegate to the IAiBidNormal implementation
    }

    fn get_bid_normal(&self, seat: &Seat) -> f32 {
        self.normal.get_bid_normal(seat) // Delegate to the IAiBidNormal implementation
    }

    fn get_bid_with_hard_diff(
        &self,
        seat: &Seat,
        table: &Table,
        round: &Round,
        final_score: i16,
    ) -> i16 {
        let sr_bid = self.get_bid_normal(seat);
        let mut num = sr_bid;
        let player_id = seat.id;
        let turn_bid_state =
            self.get_turn_bid_state(player_id, table, round, final_score, table.limit_bag);
        if self.is_can_bid_nil(sr_bid, seat, &turn_bid_state, final_score as f32) {
            return 0;
        }
        let mut num2 = 0.0;
        if turn_bid_state.is_last_player_bid && turn_bid_state.leading_bid >= 4 {
            num2 -= 0.4;
        }
        if table.rounds.len() < 5 {
            num2 += 0.4;
        }
        num += num2;
        let mut num3 = if (turn_bid_state.team_match_score as f32) < (final_score as f32 * 0.5) {
            if num > 5.0 {
                (num + 0.255).floor() as i16
            } else {
                (num + 0.501).floor() as i16
            }
        } else {
            if num > 5.0 {
                (num + 0.255).floor() as i16
            } else {
                (num + 0.499).floor() as i16
            }
        };
        if turn_bid_state.is_last_player_bid {
            let num4 = turn_bid_state.leading_bid
                + turn_bid_state.partner_bid
                + turn_bid_state.pre_player_bid;
            if num4 + num3 >= 13 {
                let mut num5 = 13 - num4;
                if num5 <= 0 {
                    num5 = 1;
                }
                num3 = if num3 - num5 > 3 { num3 - 3 } else { num5 };
            }
        }
        if num3 <= 0 {
            num3 = 1;
        }
        return num3;
    }

    fn get_bid_suit_spades(&self, seat: &Seat) -> f32 {
        return self.normal.get_bid_normal(seat);
    }

    fn is_can_bid_nil(
        &self,
        suit_rank_bid: f32,
        seat: &Seat,
        bid_state: &TurnBidState,
        _final_score: f32,
    ) -> bool {
        if suit_rank_bid > 1.34 {
            return false;
        }
        //spades >= 3 or has J Q K A
        let mut sc = &seat.cards[Suit::Spade];
        let count = sc.n;

        if count >= 3
            || sc.bucket[11] > 0
            || sc.bucket[12] > 0
            || sc.bucket[13] > 0
            || sc.bucket[1] > 0
        {
            return false;
        }
        // has joker
        sc = &seat.cards[Suit::Joker];
        if sc.n > 0 {
            return false;
        }

        if !bid_state.is_leading_player && bid_state.pre_player_bid == 0 {
            return false;
        }
        // has J Q K J not bid 0
        for index in 0..=3u8 {
            let suit = Suit::from_u8(index).unwrap();
            let sc = &seat.cards[suit];
            if sc.n > 0 {
                //some suit has A and count < 3 or  has no 2 3 4
                if sc.bucket[1] > 0 && sc.n <= 3
                    || sc.bucket[2] == 0 && sc.bucket[3] == 0 && sc.bucket[4] == 0
                {
                    return false;
                }
                //some suit only one but >=J
                if sc.n == 1
                    && (sc.bucket[11] > 0
                        || sc.bucket[12] > 0
                        || sc.bucket[13] > 0
                        || sc.bucket[1] > 0)
                {
                    return false;
                }
            }
        }
        if bid_state.is_last_player_bid && bid_state.leading_bid == 0 {
            return true;
        }
        false
    }
}

//黑桃计算 Q K A 非黑桃计算 K A
// fn get_greater_queen_card_num(list: &Vec<PokerCard>) -> i16 {
//     let mut num = 0;
//     let mut spades_pile = Vec::new();

//     for item in list.iter() {
//         if !item.is_trump_card() {
//             if item.number == 1 || item.number == 13 {
//                 num += 1;
//             }
//         } else {
//             spades_pile.push(*item);
//         }
//     }
//     for item in spades_pile.iter() {
//         if item.get_number() >= 12 {
//             num += 1;
//         }
//     }
//     num
// }
